#include "CBL_Subscriber.h"

CB_NAMESPACE_START

	// -----------------------------------------------------------------------------------------------------------------
	//	ISubscriptionListener
	// -----------------------------------------------------------------------------------------------------------------

	ISubscriptionListener::~ISubscriptionListener()
	{
		while (!m_Hosts.empty())
		{
			m_Hosts.front()->UnsubscribeListener(*this);
		}
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionListener::OnUnsubscribe(ISubscriptionHost& _rHost)
	{
		CSubscriptionHostList::iterator HostIter = std::find(m_Hosts.begin(), m_Hosts.end(), &_rHost);
		if (HostIter != m_Hosts.end())
			m_Hosts.erase(HostIter);
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionListener::OnSubscribe(ISubscriptionHost& _rHost)
	{
		m_Hosts.push_back(&_rHost);
	}

	// -----------------------------------------------------------------------------------------------------------------
	//	ISubscriptionHost
	// -----------------------------------------------------------------------------------------------------------------

	ISubscriptionHost::ISubscriptionHost(uint32 _NumTypes)
	: m_NumTypes(_NumTypes)
	{
		m_pSubscriptions = new CSubscriberList[m_NumTypes];
	}

	// -----------------------------------------------------------------------------------------------------------------

	ISubscriptionHost::~ISubscriptionHost()
	{
		for (uint32 i(0u); i<m_NumTypes; ++i)
			UnsubscribeType(i);
		
		delete[] m_pSubscriptions;
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionHost::Subscribe(uint32 _MessageType, ISubscriptionListener& _rListener, char* _pName)
	{
		if (Debug::Verify(_MessageType <= m_NumTypes))
		{
			m_pSubscriptions[_MessageType].push_back(&_rListener);
			_rListener.OnSubscribe(*this);
			
			if (_pName != NULL)
			{
				ISubscriptionListener* pExistingListener = GetListenerByName(_pName);
				
				Debug::Assert(	(pExistingListener == NULL) || (pExistingListener == &_rListener),
								"There is already a different subscription listener registered for name \"%s\"",
								_pName);
				
				if (pExistingListener == NULL)
				{
					std::string Name(_pName);
					m_SubscriberMap.insert(CSubscriberMap::value_type(Name, &_rListener));
				}
			}
		}		
	}

	// -----------------------------------------------------------------------------------------------------------------
	
	ISubscriptionListener* ISubscriptionHost::GetListenerByName(char* _pName)
	{
		std::string Name(_pName);
		CSubscriberMap::iterator ListenerIter = m_SubscriberMap.find(Name);
		
		if (ListenerIter != m_SubscriberMap.end())
			return ListenerIter->second;
		
		return NULL;
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionHost::Unsubscribe(uint32 _MessageType, ISubscriptionListener& _rListener)
	{
		if (Debug::Verify(_MessageType <= m_NumTypes))
		{
			CSubscriberList& rTypeList = m_pSubscriptions[_MessageType];
			CSubscriberList::iterator Iter = std::find(rTypeList.begin(), rTypeList.end(), &_rListener);
			(*Iter)->OnUnsubscribe(*this);
			rTypeList.erase(Iter);
		}
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionHost::UnsubscribeListener(ISubscriptionListener& _rListener)
	{
		for (uint32 i(0u); i<m_NumTypes; ++i)
			Unsubscribe(i, _rListener);
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionHost::UnsubscribeType(uint32 _MessageType)
	{
		if (Debug::Verify(_MessageType <= m_NumTypes))
		{
			CSubscriberList& rTypeList = m_pSubscriptions[_MessageType];
			while (!rTypeList.empty())
			{
				rTypeList.back()->OnUnsubscribe(*this);
				rTypeList.pop_back();
			}
		}
	}

	// -----------------------------------------------------------------------------------------------------------------

	void ISubscriptionHost::CallSubscribers(uint32 _MessageType, void* _pData)
	{
		if (Debug::Verify(_MessageType <= m_NumTypes))
		{
			CSubscriberList& rTypeList = m_pSubscriptions[_MessageType];
			
			const CSubscriberList::iterator EndIter = rTypeList.end();
			for (	CSubscriberList::iterator Iter = rTypeList.begin();
					Iter != EndIter;
					++Iter)
			{
				(*Iter)->HandleMessage(_MessageType, *this, _pData);
			}
		}
	}

CB_NAMESPACE_END